package com.ahui.util;


import com.ahui.constant.FileExtensionConstant;
import com.ahui.constant.ImageConstant;
import com.ahui.constant.MimeTypeEnum;
import com.ahui.domain.Pair;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.imaging.ImageInfo;
import org.apache.commons.imaging.Imaging;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.util.IOUtils;
import org.apache.sanselan.Sanselan;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * @author : ph.li
 * @date : 2023/7/30 13:15
 */
@Slf4j
public class TifUtil {

    private static final int DPI_DIFFERENCE = 5;

    public static List<String> tif2img(File file, String outputPath, String type) {
        List<String> fileList = new ArrayList<>();
        // 判断文件是否为tiff文件
        if (!FileUtil.isTifFile(file)) {
            log.warn("文件{}不是tiff文件", FilenameUtils.getFullPath(file.getName()));
            return fileList;
        }

        ImageInputStream imageInputStream = null;
        try {
            imageInputStream = ImageIO.createImageInputStream(file);
            Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(imageInputStream);
            if (imageReaders.hasNext()) {
                ImageReader reader = imageReaders.next();
                reader.setInput(imageInputStream);
                int pageNum = reader.getNumImages(true);
                log.info("tif文件总页数: {}。", pageNum);
                for (int i = 0; i < pageNum; i++) {
                    log.info("开始转换tif文件第 {} 页...", i + 1);
                    BufferedImage image = reader.read(i);
                    // 在Windows系统上，它返回“\”；在Unix和Linux系统上，它返回“/”。使用File.separator方法的好处是能够跨平台运行，在不同的操作系统上正确地处理文件路径。
                    // FilenameUtils.getBaseName(file.getName()) 获取文件名
                    String fileOutputPath = outputPath + File.separator + FilenameUtils.getBaseName(file.getName()) + "_" + (i + 1) + "." + type;
                    ImageIO.write(image, type, new File(fileOutputPath));
                    log.info("转换tif文件第 {} 页成功，文件路径：{}。", i, fileOutputPath);
                    fileList.add(fileOutputPath);
                }
            }
        } catch (IOException e) {
            log.error("convert tiff to img failed！", e);
        } finally {
            try {
                assert imageInputStream != null;
                imageInputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return fileList;
    }

    public static List<String> tiff2Img1(File tif, String savePath) {
        List<String> fileList = new ArrayList<>();
        boolean isNeedHandle = isNeedHandle(tif);
        if (isNeedHandle) {
            try (ImageInputStream ins = ImageIO.createImageInputStream(tif)) {
                ImageReader reader = ImageIO.getImageReaders(ins).next();
                reader.setInput(ins);
                int pageCount = reader.getNumImages(true);
                log.info("tif文件总页数: {}。", pageCount);
                for (int i = 0; i < pageCount; i++) {
                    log.info("开始转换tif文件第 {} 页...", i + 1);
                    String filePath = savePath + File.separator + FilenameUtils.getBaseName(tif.getName()) + "_" + (i + 1) + FileExtensionConstant.JPG;
                    BufferedImage image = reader.read(i);

                    //BufferedImage转InputStream
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write(image, "tif", baos);
                    InputStream is = new ByteArrayInputStream(baos.toByteArray());
                    Pair<Integer, Integer> size = getTifSizeByDpi(is);
                    //还原原始尺寸
                    image = resize(image, size.getLeft(), size.getRight());

                    image = autoResizeA4(image);
                    ImageIO.write(image, MimeTypeEnum.JPG.name(), new File(filePath));
                    log.info("转换tif文件第 {} 页成功，文件路径：{}。", i, filePath);
                    fileList.add(filePath);
                }
            } catch (IOException e) {
                log.error("convert tiff to img failed！", e);
            }
        }
        return fileList;
    }

    private static boolean isNeedHandle(File f) {
        org.apache.sanselan.ImageInfo imageInfo = null;
        try {
            imageInfo = Sanselan.getImageInfo(f);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        int physicalWidthDpi = imageInfo.getPhysicalWidthDpi();
        int physicalHeightDpi = imageInfo.getPhysicalHeightDpi();
        int imgDpiDifference = Math.abs(physicalHeightDpi - physicalWidthDpi);
        boolean isNeedHandle = imgDpiDifference < DPI_DIFFERENCE ? false : true;
        return isNeedHandle;
    }

    private static Pair<Integer, Integer> getTifSizeByDpi(InputStream inputStream) {
        ImageInfo imageInfo = null;
        try {
            byte[] bytes = IOUtils.toByteArray(inputStream);
            imageInfo = Imaging.getImageInfo(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        if (imageInfo.getPhysicalWidthDpi() / (float) imageInfo.getPhysicalHeightDpi() > 1.5) {
            float widthValue = (float) imageInfo.getWidth() / imageInfo.getPhysicalWidthDpi();
            float heightValue = (float) imageInfo.getHeight() / imageInfo.getPhysicalHeightDpi();
            float ratio = widthValue / heightValue;
            int newWidthSize = (int) (imageInfo.getHeight() * ratio);
            return new Pair<>(newWidthSize, imageInfo.getHeight());
        }
        return new Pair<>(imageInfo.getWidth(), imageInfo.getHeight());
    }

    //根据缩放比例调整图片大小
    public static BufferedImage resize(BufferedImage img, int newW, int newH) {
        Image tmp = img.getScaledInstance(newW, newH, Image.SCALE_SMOOTH);
        BufferedImage bi = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = bi.createGraphics();
        g2d.drawImage(tmp, 0, 0, null);
        g2d.dispose();
        return bi;
    }

    public static BufferedImage autoResizeA4(BufferedImage img) {
        int width = img.getWidth();
        int height = img.getHeight();

        float ratio;
        if (img.getWidth() > img.getHeight()) {
            if (img.getWidth() < ImageConstant.A4_MAX_SHORT) {
                ratio = ImageConstant.A4_MAX_SHORT / width;
                height = (int) (ImageConstant.A4_MAX_LONG / ratio);
                return resize(img, width, height);
            }
            width = ImageConstant.A4_MAX_SHORT;
            height = ImageConstant.A4_MAX_LONG;
        } else {
            if (img.getHeight() < ImageConstant.A4_MAX_LONG) {
                ratio = ImageConstant.A4_MAX_LONG / height;
                width = (int) (ImageConstant.A4_MAX_SHORT / ratio);
                return resize(img, width, height);
            }
            width = ImageConstant.A4_MAX_SHORT;
            height = ImageConstant.A4_MAX_LONG;
        }
        return resize(img, width, height);
    }


}
